
package com.kugou.game.sdk.ui.widget;

import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.PopupWindow;

import java.util.ArrayList;

/**
 * @author liaodongmingRabbit
 */
public abstract class KGPopupWindow extends PopupWindow {

    private static final int MEASURE_AND_LAYOUT_DONE = 1 << 1;

    private final int[] mLocation = new int[2];

    private final Rect mRect = new Rect();

    private int mPrivateFlags;

    private Context mContext;

    private boolean mDismissOnClick;

    private int mArrowOffsetY;

    private int mPopupY;

    private int mPopupX = 0;

    private boolean mIsOnTop;

    private int mScreenHeight;

    private int mScreenWidth;

    private boolean mIsDirty;

    private OnActionItemClickListener mOnActionItemClickListener;

    private ArrayList<ActionItem> mActionItems = new ArrayList<ActionItem>();

    private int mGravity = Gravity.NO_GRAVITY;

    private int mOffsetX;

    private int mOffsetY;

    /**
     * Interface that may be used to listen to clicks on quick actions.
     * 
     * @author Benjamin Fellous
     * @author Cyril Mottier
     */
    public static interface OnActionItemClickListener {
        /**
         * Clients may implement this method to be notified of a click on a
         * particular quick action.
         * 
         * @param position Position of the quick action that have been clicked.
         */
        void onActionItemClicked(KGPopupWindow window, int position);
    }

    /**
     * Creates a new KGPopupWindow for the given context.
     * 
     * @param context The context in which the KGPopupWindow is running in
     */
    public KGPopupWindow(Context context) {
        super(context);

        mContext = context;

        initializeDefault();

        setFocusable(true);
        setTouchable(true);
        setOutsideTouchable(true);
        setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
        setHeight(WindowManager.LayoutParams.WRAP_CONTENT);

        final WindowManager windowManager = (WindowManager) mContext
                .getSystemService(Context.WINDOW_SERVICE);
        mScreenWidth = windowManager.getDefaultDisplay().getWidth();
        mScreenHeight = windowManager.getDefaultDisplay().getHeight();

    }

    /**
     * Equivalent to {@link PopupWindow#setContentView(View)} but with a layout
     * identifier.
     * 
     * @param layoutId The layout identifier of the view to use.
     */

    public void setContentView(int layoutId) {
        setContentView(LayoutInflater.from(mContext).inflate(layoutId, null));
    }

    private void initializeDefault() {
        mDismissOnClick = true;
        mArrowOffsetY = 5;
    }

    /**
     * Returns the arrow offset for the Y axis.
     * 
     * @see {@link #setArrowOffsetY(int)}
     * @return The arrow offset.
     */
    public int getArrowOffsetY() {
        return mArrowOffsetY;
    }

    /**
     * Sets the arrow offset to a new value. Setting an arrow offset may be
     * particular useful to warn which view the KGPopupWindow is related to. By
     * setting a positive offset, the arrow will overlap the view given by
     * {@link #show(View)}. The default value is 5dp.
     * 
     * @param offsetY The offset for the Y axis
     */
    public void setArrowOffsetY(int offsetY) {
        mArrowOffsetY = offsetY;
    }

    /**
     * Returns the width of the screen.
     * 
     * @return The width of the screen
     */
    protected int getScreenWidth() {
        return mScreenWidth;
    }

    /**
     * Returns the height of the screen.
     * 
     * @return The height of the screen
     */
    protected int getScreenHeight() {
        return mScreenHeight;
    }

    /**
     * By default, a {@link KGPopupWindow} is dismissed once the user clicked on
     * a {@link ActionItem}. This behavior can be changed using this method.
     * 
     * @param dismissOnClick True if you want the {@link KGPopupWindow} to be
     *            dismissed on click else false.
     */
    public void setDismissOnClick(boolean dismissOnClick) {
        mDismissOnClick = dismissOnClick;
    }

    public boolean getDismissOnClick() {
        return mDismissOnClick;
    }

    /**
     * @param listener
     */
    public void setOnActionItemClickListener(OnActionItemClickListener listener) {
        mOnActionItemClickListener = listener;
    }

    /**
     * Add a new ActionItem to this {@link KGPopupWindow}. Adding a new
     * {@link ActionItem} while the {@link KGPopupWindow} is currently being
     * shown does nothing. The new {@link ActionItem} will be displayed on the
     * next call to {@link #show(View)}.
     * 
     * @param action The new {@link ActionItem} to add
     */
    public void addActionItem(ActionItem action) {
        if (action != null) {
            mActionItems.add(action);
            mIsDirty = true;
        }
    }

    /**
     * Removes all {@link ActionItem} from this {@link KGPopupWindow}.
     */
    public void clearAllActionItems() {
        if (!mActionItems.isEmpty()) {
            mActionItems.clear();
            mIsDirty = true;
        }
    }

    /**
     * Call that method to display the {@link KGPopupWindow} anchored to the
     * given view.
     * 
     * @param anchor The view the {@link KGPopupWindow} will be anchored to.
     */
    public void show(View anchor) {
        initAnchorView(anchor);
        showAtLocation(anchor, mPopupX);
    }

    private void initAnchorView(View anchor) {
        final View contentView = getContentView();

        if (contentView == null) {
            throw new IllegalStateException(
                    "You need to set the content view using the setContentView method");
        }

        // Replaces the background of the popup with a cleared background
        setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));

        final int[] loc = mLocation;
        anchor.getLocationOnScreen(loc);
        mRect.set(loc[0], loc[1], loc[0] + anchor.getWidth(), loc[1] + anchor.getHeight());

        if (mIsDirty) {
            clearActionItems();
            populateActionItems(mActionItems);
        }

        onMeasureAndLayout(mRect, contentView);

        if ((mPrivateFlags & MEASURE_AND_LAYOUT_DONE) != MEASURE_AND_LAYOUT_DONE) {
            throw new IllegalStateException(
                    "onMeasureAndLayout() did not set the widget specification by calling"
                            + " setWidgetSpecs()");
        }

        showArrow();
        prepareAnimationStyle();
        onShow();
    }

    public void show(View anchor, int paddingX) {
        initAnchorView(anchor);
        showAtLocation(anchor, paddingX);
    }

    private void showAtLocation(View anchor, int padding) {
        showAtLocation(anchor, mGravity, padding, mPopupY);
    }

    @Override
    public void showAtLocation(View anchor, int gravity, int x, int y) {
        initAnchorView(anchor);
        super.showAtLocation(anchor, gravity, x, y);
    }

    @Override
    public void showAsDropDown(View anchor) {
        initAnchorView(anchor);
        super.showAsDropDown(anchor);
    }

    @Override
    public void showAsDropDown(View anchor, int xoff, int yoff) {
        initAnchorView(anchor);
        super.showAsDropDown(anchor, xoff, yoff);
    }

    protected void clearActionItems() {
        if (!mActionItems.isEmpty()) {
            onClearActionItems();
        }
    }

    protected void onClearActionItems() {
    }

    protected abstract void populateActionItems(ArrayList<ActionItem> actionItems);

    protected abstract void onMeasureAndLayout(Rect anchorRect, View contentView);

    protected void setWidgetSpecs(int popupY, boolean isOnTop) {
        mPopupY = popupY;
        mIsOnTop = isOnTop;
        mPrivateFlags |= MEASURE_AND_LAYOUT_DONE;
    }

    protected void setWidgetSpecsX(int popupX) {
        mPopupX = popupX;
    }

    protected abstract void showArrow();

    protected abstract void prepareAnimationStyle();

    protected Context getContext() {
        return mContext;
    }

    protected OnActionItemClickListener getOnActionItemClickListener() {
        return mOnActionItemClickListener;
    }

    protected View findViewById(int id) {
        return getContentView().findViewById(id);
    }

    protected void setDirty(boolean isDirty) {
        this.mIsDirty = isDirty;
    }

    /**
     * 显示之前调用
     */
    protected abstract void onShow();

    /**
     * 消失之前调用
     */
    protected abstract void onDismiss();

    @Override
    public void dismiss() {
        onDismiss();
        super.dismiss();
    }

    public void setGravity(int gravity) {
        this.mGravity = gravity;
    }

}
